package com.shiyun.disaster_station.utils;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.impl.CoordinateArraySequenceFactory;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;

import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * 类 描 述: 地理坐标工具
 * 作   者: 史 云
 *
 * @author 史 云
 * 版   本: 1.0.0
 * 时   间: 2021年12月17日  10:59:00
 */
@Slf4j
public class GeometryUtil {
    static WKTReader reader = new WKTReader();
    static CoordinateArraySequenceFactory sequenceFactory;
    static GeometryFactory geometryFactory;
    static double UNIT_OF_CONVERSION_IN_KILOMETERS = NumberUtil.round(6371000 * Math.PI / 180_000, 3, RoundingMode.HALF_UP).doubleValue();

    static {
        sequenceFactory = CoordinateArraySequenceFactory.instance();
        geometryFactory = new GeometryFactory(new PrecisionModel(), 0);
    }

    /**
     * 方法描述: 转换为几何类型
     * 作   者: 史 云
     * 时   间: 2021年12月17日 11:11:00
     */
    public static Geometry createPoint(String wktPoint) {
        if (StrUtil.isBlank(wktPoint)) {
            return null;
        }
        try {
            return reader.read(wktPoint);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 方法描述: 根据经纬度创建Geometry对象
     * 作   者: 史 云
     * 时   间: 2021年12月24日 16:18:00
     */
    public static Point createPoint(double lon, double lat) {
        CoordinateSequence coordinateSequence = geometryFactory.getCoordinateSequenceFactory().create(new Coordinate[]{new Coordinate(lon, lat)});
        return new Point(coordinateSequence, geometryFactory);
    }

    /**
     * 方法描述: 根据经纬度数组转换为Point
     * 作    者: 史 云
     * 时    间: 2022年04月16日  16:48:41
     */
    public static Point createPointByArray(List<Double> arrays) {
        CoordinateSequence coordinateSequence = geometryFactory.getCoordinateSequenceFactory().create(new Coordinate[]{new Coordinate(arrays.get(0), arrays.get(1))});
        return new Point(coordinateSequence, geometryFactory);
    }

    /**
     * 方法描述: 创建一条线
     * 作   者: 史 云
     * 时   间: 2022年12月27日 16:36:00
     */
    public static LineString createLineString(List<Coordinate> coordinateList) {
        CoordinateSequence coordinateSequence = getCoordinateSequence(coordinateList);
        return new LineString(coordinateSequence, geometryFactory);
    }

    /**
     * 方法描述: 获取CoordinateSequence
     * 作   者: 史 云
     * 时   间: 2022年12月27日 16:39:00
     */
    private static CoordinateSequence getCoordinateSequence(List<Coordinate> coordinateList) {
        Coordinate[] coordinates = new Coordinate[coordinateList.size()];
        return geometryFactory.getCoordinateSequenceFactory().create(coordinateList.toArray(coordinates));
    }

    /**
     * 方法描述: 封闭的线
     * 作   者: 史 云
     * 时   间: 2022年12月27日 16:39:00
     */
    public static LinearRing createLinerRing(List<Coordinate> coordinateList) {
        // 为了封闭图形
        coordinateList.add(coordinateList.get(0));
        CoordinateSequence coordinateSequence = getCoordinateSequence(coordinateList);
        return new LinearRing(coordinateSequence, geometryFactory);
    }

    /**
     * 方法描述: 实心的面
     * 作   者: 史 云
     * 时   间: 2022年12月27日 16:41:00
     */
    public static Polygon createPolygon(List<Coordinate> coordinateList) {
        return new Polygon(createLinerRing(coordinateList), new LinearRing[0], geometryFactory);
    }

    /**
     * 方法描述: 实心的坐标
     * 作    者: 史 云
     * 时    间: 2022年06月07日  11:39:25
     */
    public static Polygon createPolygon(String wkt) throws ParseException {
        return new Polygon(new LinearRing(sequenceFactory.create(reader.read(wkt).getCoordinates()),geometryFactory), new LinearRing[0], geometryFactory);
    }

    /**
     * 方法描述: Geometry转Point
     * 作   者: 史 云
     * 时   间: 2022年12月28日 13:46:00
     */
    public static Point geometryToPoint(Geometry geometry) {
        Coordinate coordinate = geometry.getCoordinates()[0];
        return createPoint(coordinate.x, coordinate.y);
    }

    /**
     * 方法描述: 度转为公里
     * 作   者: 史 云
     * 时   间: 2022年01月05日 10:36:00
     */
    public static Double angleToKilometre(double angle) {
        return NumberUtil.round(angle * UNIT_OF_CONVERSION_IN_KILOMETERS, 3, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 方法描述: 公里转度
     * 作   者: 史 云
     * 时   间: 2022年01月05日 10:38:00
     */
    public static Double kilometreToAngle(double kilometre) {
        return NumberUtil.round(kilometre / UNIT_OF_CONVERSION_IN_KILOMETERS, 3, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 方法描述: 根据地理对象获取坐标数组
     * 作   者: 史 云
     * 时   间: 2022年01月10日 10:29:00
     */
    public static List<Double> pointToCord(Geometry point) {
        Coordinate coordinate = point.getCoordinates()[0];
        List<Double> rsp = new ArrayList<>(2);
        Double v = NumberUtil.round(coordinate.getX(), 6).doubleValue();
        Double y = NumberUtil.round(coordinate.getY(), 6).doubleValue();
        rsp.add(v);
        rsp.add(y);
        return rsp;
    }

    /**
     * 方法描述: 计算点到点的距离:单位：公里
     * 作    者: 史 云
     * 时    间: 2022年04月16日  16:41:57
     */
    public static Double pointToPoint(Geometry head, Geometry tail) {
        try {
            return LocUtils.calculateKilometre(head.getCoordinate().getY(), head.getCoordinate().getX(), tail.getCoordinate().getY(), tail.getCoordinate().getX());
        } catch (Exception e) {
            log.error("计算点距离失败:{}", e.getMessage());
            return 0.0;
        }
    }

}
